#!/usr/bin/python
#
# Copyright 2008 Wepoco.  http://www.wepoco.org/
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import sys
import time
from StringIO import StringIO
from datetime import datetime
from xml.etree.ElementTree import parse
from xml.etree.ElementTree import Element, SubElement, ElementTree, fromstring
from datetime import timedelta

from mapskey import MAPS_API_KEY

class TimePlace:
    def __init__(self,seg=None):
        self.when = None
        self.lat = None
        self.lon = None

        if seg != None:
            timetext = seg.findtext('{http://www.topografix.com/GPX/1/0}time')
            if timetext:
                self.when = datetime.strptime(timetext,'%Y-%m-%dT%H:%M:%S')
                self.lat = float( seg.attrib["lat"] )
                self.lon = float( seg.attrib["lon"] )
                pass
            pass
        return

    

class GPXTimeline:
    def __init__(self, gpx_in=None):
        if gpx_in:
            self.tree =  parse(StringIO(gpx_in))
            self.root = self.tree.getroot()
            (ns,tag) = self.ns_tag(self.root)
            if tag != 'gpx':
                self.tree = None
                self.root = None
                pass
            pass
        else:
            self.tree = None
            self.root = None
            pass
        pass
    
        
    def ns_tag( self, el ):
        if el.tag[0] == '{':
            return el.tag[1:].split("}")
        else:
            return (None, el.tag)
        pass

    # Return a TimePlace for the nearest track time and place to this time.
    def getLocation( self, dateTime ):
        for track in self.root:
            for seg in track:
                (ns,tag) = self.ns_tag(seg)
                if tag == 'trkseg':
                    wpt_start = TimePlace(seg[0])
                    wpt_end = TimePlace(seg[-1])
                    if dateTime < wpt_end.when:
                        # It's this track segment, or the previous one.
                        if dateTime < wpt_start.when:
                            # Assume location is the start of this segment.
                            # Though it could be the end of the previous one.
                            # Or somewhere else we don't know about.
                            return wpt_start
                        else:
                            # It's somewhere in this segment.
                            for pt in seg:
                                wpt = TimePlace(pt)
                                if wpt.when:
                                    if dateTime < wpt.when:
                                        return wpt
                                    pass
                                pass
                            pass
                        return wpt_end
                        pass
                    pass
                pass
            pass
        return None
    
    def getPhotoLocations( self, pics, slip=0 ):
        # pics is a sorted list of Photos
        idx = 0
        delta = timedelta(seconds=slip)
        for track in self.root:
            for seg in track:
                (ns,tag) = self.ns_tag(seg)
                if tag == 'trkseg':
                    wpt_start = TimePlace(seg[0])
                    wpt_end = TimePlace(seg[-1])
                    while (pics[idx].when + delta) < wpt_end.when:
                        # It's this track segment, or the previous one.
                        if (pics[idx].when + delta) < wpt_start.when:
                            # Assume location is the start of this segment.
                            # Though it could be the end of the previous one.
                            # Or somewhere else we don't know about.
                            pics[idx].lat = wpt_start.lat
                            pics[idx].lon = wpt_start.lon
                            idx = idx+1
                            if idx == len(pics):
                                return
                        else:
                            # It's somewhere in this segment.
                            for pt in seg:
                                wpt = TimePlace(pt)
                                if wpt.when:
                                    if (pics[idx].when + delta) < wpt.when:
                                        pics[idx].lat = wpt.lat
                                        pics[idx].lon = wpt.lon
                                        idx = idx+1
                                        if idx == len(pics):
                                            return
                                    pass
                                pass
                            pass
                        #return wpt_end
                        pass
                    pass
                pass
            pass
        return None
        

    def timeline( self, gpx_in=None, debug=False):
        if gpx_in:
            tree =  parse(StringIO(gpx_in))
            root = tree.getroot()
            (ns,tag) = self.ns_tag(root)
        else:
            tree = self.tree
            root = self.root
            pass
        results = []
        elem = root
        (ns,tag) = self.ns_tag(elem)
        if tag != 'gpx':
            return None
            pass
        
        #print "root contains", len(elem), "tracks" 
        for track in elem:
            #print "track contains", len(track), "segs" 
            for seg in track:
                (ns,tag) = self.ns_tag(seg)
                if tag == 'trkseg':
                    wpt_start = TimePlace(seg[0])
                    wpt_end = TimePlace(seg[-1])
                    if debug:
                        max = len(seg)
                        if max > 10:
                            max = 10
                            pass
                        for i in range(max):
                            results.append((TimePlace(seg[i]),
                                           TimePlace(seg[i+1])))
                            pass
                        pass
                    else:
                        results.append((wpt_start,wpt_end))
                    pass
                pass
            pass
        return results

    def dataXML( self, gpx_in, xml_out ):
        data = Element( 'data' )
        trackSegs = self.timeline( gpx_in )
        for ( wptStart, wptEnd ) in trackSegs:
            event = SubElement( data, 'event' )
            event.attrib['start'] = wptStart.when.strftime("%a %b %d %Y %H:%M:%S")
            event.attrib['end'] = wptEnd.when.strftime("%a %b %d %Y %H:%M:%S")
            event.attrib['title'] = "track"
            event.attrib['isDuration'] = "true"
            # See http://code.google.com/apis/maps/documentation/staticmaps/ for documentation
            # on Google's static maps API.
            event.attrib['image']="http://maps.google.com/staticmap?maptype=mobile&zoom=8&size=128x128&markers=%s,%s&key=%s" % ( wptStart.lat, wptStart.lon, MAPS_API_KEY )
            pass
        xml_out.write( '<?xml version="1.0" encoding="UTF-8"?>\n' )
        ElementTree( data ).write( xml_out )
        

        

#data=Fri Apr 18 17:02:50Z 2008  fmt=%a %b %d %H:%M:%S %Y

#2008-02-08T08:55:06 %Y-%m-%dT%H:%M:%S

def main():
    GPXTimeline().dataXML(open(sys.argv[1],'r').read(), open(sys.argv[2],"w"))
    pass

if __name__ == '__main__':
    main()
